﻿using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using System.Text;
using System.Security.Cryptography;
using System.Web.UI.HtmlControls;
using Slam.FieldTypes;
using Microsoft.SharePoint.Security;
using System.Security.Permissions;
using Slam;
using SlamCms.SharePoint.Core;

namespace SlamCms.SharePoint.FieldTypes
{
	public partial class EnhancedFileUploadFieldControl : SlamFieldControl
	{
		public string AllowedFileExtensions
		{
			get;
			set;
		}

		public bool CreateUniqueFolders
		{
			get;
			set;
		}

		public string SaveDocumentLibrary
		{
			get;
			set;
		}

		public string SavePictureLibrary
		{
			get;
			set;
		}
		
		public string SaveLocation
		{
			get;
			set;
		}

		public string S3AccessKey
		{
			get;
			set;
		}

		public string S3SecretKey
		{
			get;
			set;
		}

		public string S3Bucket
		{
			get;
			set;
		}

		public string StorageMode
		{
			get;
			set;
		}

		public bool UniqueFileNames
		{
			get;
			set;
		}

		public int MaxFilesPerListItem
		{
			get;
			set;
		}

		protected override string DefaultTemplateName
		{
			get
			{
				return "SlamCMSEnhancedFileUploadFieldControl";
			}
		}

		[SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
		public override void Validate()
		{
			if ((base.ControlMode != SPControlMode.Display) && base.IsValid && base.Field.Required)
			{
				base.Validate();
				if (String.IsNullOrEmpty(hdnCurrentValue.Value))
				{
					base.IsValid = false;
					base.ErrorMessage = SPResource.GetString("MissingRequiredField", new object[0]);
				}
			}
		}

		
		protected override void CreateChildControls()
		{
			base.CreateChildControls();

			bool addCssReference = true;
			string cssInclude = String.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" media=\"all\" />", ResolveUrl("~/_layouts/1033/STYLES/SlamCms.enhanceduploadfield.css"));

			foreach (Control control in Page.Header.Controls)
			{
				if (control is LiteralControl && ((LiteralControl)control).Text == cssInclude)
				{
					addCssReference = false;
				}
			}
			if (addCssReference)
			{
				Page.Header.Controls.Add(new LiteralControl(cssInclude));
			}

			if (IsEditOrNew())
			{
				FindControls();
				ltStorageMode.Text = StorageMode;

				switch (StorageMode)
				{
					case "Amazon S3":
						if (!(String.IsNullOrEmpty(S3AccessKey) || String.IsNullOrEmpty(S3Bucket) || String.IsNullOrEmpty(S3SecretKey)))
						{
							ltAccessKey.Text = S3AccessKey;
							ltPolicy.Text = ConstructAwsS3Policy();
							ltSignature.Text = CreateSignature(ltPolicy.Text);
							ltBucket.Text = S3Bucket;
							ltAcl.Text = "public-read";
							//ltMaxFilesPerListItem.Text = "1";
							if (string.IsNullOrEmpty(AllowedFileExtensions))
								ltAllowedFileExtensions.Text = "*";
							else
								ltAllowedFileExtensions.Text = AllowedFileExtensions;
						}
						else
						{
							ltCriticalError.Text = "Amazon S3 Configuration values not set.  Please edit field and set Bucket name, Access Key, and Secret Key.";
						}
						break;
					case "Document Library":
						if (!String.IsNullOrEmpty(SaveDocumentLibrary))
						{
							ltCurrentSiteUrl.Text = SPContext.Current.Web.Url;
							ltAcl.Text = "public-read";
							//ltMaxFilesPerListItem.Text = "1";
							if (string.IsNullOrEmpty(AllowedFileExtensions))
								ltAllowedFileExtensions.Text = "*";
							else
								ltAllowedFileExtensions.Text = AllowedFileExtensions;
							ltLibraryID.Text = SaveDocumentLibrary;
							var library = GetDocumentLibrary(SaveDocumentLibrary);
							//ltLibraryUrl.Text = library.ParentWeb.Url + "/" + library.Title;
							ltLibraryUrl.Text = library.ParentWeb.Url.TrimEnd('/') + "/" + library.RootFolder.Url.TrimStart('/');
							var siteCollection = library.ParentWeb.Site;
							//ltServerRelativeUrl.Text = (siteCollection.ServerRelativeUrl.TrimEnd('/') + "/" + library.ParentWeb.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length).TrimStart('/').TrimEnd('/') + "/" + library.RootFolder.Url.TrimStart('/'));
							ltServerRelativeUrl.Text = (library.ParentWeb.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length).TrimStart('/').TrimEnd('/') + "/" + library.RootFolder.Url.TrimStart('/')).TrimStart('/');

							ltSiteColUrl.Text = siteCollection.Url;

						}
						else
						{
							ltCriticalError.Text = "Document Library Configuration not set. Please edit field and set Library.";
						}

						break;
					case "Picture Library":
						if (!String.IsNullOrEmpty(SavePictureLibrary))
						{
							ltCurrentSiteUrl.Text = SPContext.Current.Web.Url;
							ltAcl.Text = "public-read";
							//ltMaxFilesPerListItem.Text = "1";
							if (string.IsNullOrEmpty(AllowedFileExtensions))
								ltAllowedFileExtensions.Text = "jpg,gif,bmp,png";
							else
								ltAllowedFileExtensions.Text = AllowedFileExtensions;
							ltLibraryID.Text = SavePictureLibrary;
							var library = GetDocumentLibrary(SavePictureLibrary);
							//ltLibraryUrl.Text = library.ParentWeb.Url + "/" + library.Title;
							ltLibraryUrl.Text = library.ParentWeb.Url.TrimEnd('/') + "/" + library.RootFolder.Url.TrimStart('/');
							var siteCollection = library.ParentWeb.Site;
							//ltServerRelativeUrl.Text = (siteCollection.ServerRelativeUrl.TrimEnd('/')+"/" + library.ParentWeb.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length).TrimStart('/').TrimEnd('/') +"/" + library.RootFolder.Url.TrimStart('/'));
							ltServerRelativeUrl.Text = (library.ParentWeb.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length).TrimStart('/').TrimEnd('/') +"/" + library.RootFolder.Url.TrimStart('/')).TrimStart('/');

							ltSiteColUrl.Text = siteCollection.Url;

						}
						else
						{
							ltCriticalError.Text = "Document Library Configuration not set. Please edit field and set Library.";
						}

						break;
					default:
						break;
				}

				

				ltMaxFilesPerListItem.Text = this.MaxFilesPerListItem.ToString();

				if (CreateUniqueFolders)
				{
					ltUniqueFolderName.Text = Guid.NewGuid().ToString() + "/";
				}

				if (UniqueFileNames)
				{
					ltUniqueFileName.Text = Guid.NewGuid().ToString();
				}

				SetFieldControlValue(ListItemFieldValue);

				ltInitScript.Text = String.Format("<script type=\"text/javascript\">{0}</script>", GetInitScript());
			}
		}

		private string GetInitScript()
		{
			StringBuilder builder = new StringBuilder();

			string uploaderVar = "uploader_"+this.ClientID;
			string settingsVar = "settings_" + this.ClientID;

			

			//builder.AppendLine("var " + settingsVar + " = new UploaderSettings('" + settingsContainer.ClientID + "', '" + displayContainer.ClientID + "');");
			builder.AppendLine("var " + uploaderVar + ";");
			builder.AppendLine("var " + settingsVar + " = new UploaderSettings('" + settingsVar + "', " + uploaderVar + ", '" + settingsContainer.ClientID + "', '" + enhancedUploadButtons.ClientID + "', '" + displayContainer.ClientID + "');");

			//builder.AppendLine("InitUploader(" + uploaderVar + ", " + settingsVar + ");");
			builder.AppendLine("InitUploader(" +settingsVar +");");

			//builder.AppendLine(String.Format("$(document).ready("+settingsVar+".DocumentReady({0}));", uploaderVar));
			builder.AppendLine("$(document).ready(" + settingsVar + ".DocumentReady());");
		   

			return builder.ToString();
		}


		protected override void OnLoad(EventArgs e)
		{
			Page.ClientScript.RegisterClientScriptInclude("jquery", ResolveUrl("~/_layouts/inc/jquery-1.6.2.min.js"));
			Page.ClientScript.RegisterClientScriptInclude("plupload", ResolveUrl("~/_layouts/inc/plupload.full.js"));

			base.OnLoad(e);

			if (IsEditOrNew())
			{
				ltCurrentListId.Text = hdnCurrentValue.ClientID;

				if (StorageMode == "Document Library" || StorageMode == "Picture Library")
				{
					long fileLength = 0;
					SlamCmsContext.SharePoint.WithElevatedPrivileges().SiteCollection().Site().List(ListId, (list, site, siteCollection) =>
					{
						if (!list.Fields.ContainsField(Field.Title + " Size"))
						{
							site.AllowUnsafeUpdates = true;
							SPField newField = list.Fields.CreateNewField("Number", Field.Title + " Size");
							newField.Hidden = true;
							list.Fields.Add(newField);
							list.Update();
							Page.Response.Redirect(Page.Request.Url.ToString());
						}
					});


					if (!String.IsNullOrEmpty(Convert.ToString(Value)))
					{
						SlamCmsContext.SharePoint.WithElevatedPrivileges().SiteCollection(siteCollection =>
						{
							using (SPWeb rootWeb = siteCollection.RootWeb)
							{
								var library = GetDocumentLibrary(SaveDocumentLibrary);
								var file = rootWeb.GetFile(Convert.ToString(Value));
								if (file != null && file.Exists)
								{
									fileLength = file.Length;
								}
							}
						});
					}
					
					if(fileLength > 0)
						SPContext.Current.ListItem[Field.Title + " Size"] = fileLength;
				}
			}
		}

		private void SetFieldControlValue(object value)
		{
			if (value != null && (String.IsNullOrEmpty(hdnCurrentValue.Value) || hdnCurrentValue.Value != value.ToString()))
			{
				hdnCurrentValue.Value = value.ToString();
			}
		}

		//public override void Validate()
		//{
		//    base.Validate();
		//    try
		//    {
				
		//    }
		//    catch (Exception ex)
		//    {
		//        IsValid = false;
		//        ErrorMessage = ex.Message;
		//    }
		//}

		public override object Value
		{
			get
			{
				this.EnsureChildControls();
				return hdnCurrentValue.Value;
			}
			set
			{
				this.EnsureChildControls();
				hdnCurrentValue.Value = value.ToString();
			}
		}
		
		#region Controls
		private HiddenField hdnCurrentValue;
		private Literal ltAccessKey;
		private Literal ltPolicy;
		private Literal ltSignature;
		private Literal ltBucket;
		private Literal ltAcl;
		private Literal ltCurrentListId;
		private Literal ltMaxFilesPerListItem;
		private Literal ltCriticalError;
		private Literal ltAllowedFileExtensions;
		private Literal ltUniqueFolderName;
		private Literal ltUniqueFileName;
		private Literal ltStorageMode;
		private Literal ltLibraryID;
		private Literal ltCurrentSiteUrl;
		private Literal ltLibraryUrl;
		private Literal ltInitScript;
		private Literal ltServerRelativeUrl;
		private Literal ltSiteColUrl;

		private HtmlGenericControl settingsContainer;
		private HtmlGenericControl enhancedUploadButtons;
		private HtmlGenericControl displayContainer;
		private Button btnAddFiles;
		#endregion

		protected bool IsEditOrNew()
		{
			return (ControlMode == SPControlMode.New || ControlMode == SPControlMode.Edit);
		}

		/// <summary>
		/// Finds and initializes all controls
		/// </summary>
		protected void FindControls()
		{
			hdnCurrentValue = TemplateContainer.FindControl("hdnCurrentValue") as HiddenField;
			ltAccessKey = TemplateContainer.FindControl("ltAccessKey") as Literal;
			ltPolicy = TemplateContainer.FindControl("ltPolicy") as Literal;
			ltSignature = TemplateContainer.FindControl("ltSignature") as Literal;
			ltBucket = TemplateContainer.FindControl("ltBucket") as Literal;
			ltAcl = TemplateContainer.FindControl("ltAcl") as Literal;
			ltCurrentListId = TemplateContainer.FindControl("ltCurrentListId") as Literal;
			ltMaxFilesPerListItem = TemplateContainer.FindControl("ltMaxFilesPerListItem") as Literal;
			ltCriticalError = TemplateContainer.FindControl("ltCriticalError") as Literal;
			ltAllowedFileExtensions = TemplateContainer.FindControl("ltAllowedFileExtensions") as Literal;
			ltUniqueFolderName = TemplateContainer.FindControl("ltUniqueFolderName") as Literal;
			ltUniqueFileName = TemplateContainer.FindControl("ltUniqueFileName") as Literal;
			ltStorageMode = TemplateContainer.FindControl("ltStorageMode") as Literal;
			ltLibraryID = TemplateContainer.FindControl("ltLibraryID") as Literal;
			ltCurrentSiteUrl = TemplateContainer.FindControl("ltCurrentSiteUrl") as Literal;
			ltLibraryUrl = TemplateContainer.FindControl("ltLibraryUrl") as Literal;
			ltInitScript = TemplateContainer.FindControl("ltInitScript") as Literal;
			ltServerRelativeUrl = TemplateContainer.FindControl("ltServerRelativeUrl") as Literal;
			ltSiteColUrl = TemplateContainer.FindControl("ltSiteColUrl") as Literal;

			settingsContainer = TemplateContainer.FindControl("settingsContainer") as HtmlGenericControl;
			enhancedUploadButtons = TemplateContainer.FindControl("enhancedUploadButtons") as HtmlGenericControl;
			displayContainer = TemplateContainer.FindControl("displayContainer") as HtmlGenericControl;
			btnAddFiles = TemplateContainer.FindControl("btnAddFiles") as Button;
			
		}

		public string ConstructAwsS3Policy()
		{	
			var policy = string.Format(@"{{ 'expiration': '{0}.000Z',
				'conditions': [
					{{ 'bucket': '{1}' }},
					{{ 'acl': 'public-read' }},
					{{ 'success_action_status': '201' }},
					['content-length-range', 0, 4398046511104],
					['starts-with', '$key', '" + ltUniqueFolderName.Text + @"' ],
					['starts-with', '$Content-Type', '' ],
					['starts-with', '$name', '" + ltUniqueFolderName.Text + @"' ],
					['starts-with', '$Filename', '']
				]
			}}", DateTime.UtcNow.Add(new TimeSpan(0, 10, 0, 0)).ToString("s"), S3Bucket);
			var encodedPolicy = Encoding.UTF8.GetBytes(policy);
			return Convert.ToBase64String(encodedPolicy);
		}

		public string CreateSignature(string policy)
		{
			var sha = new HMACSHA1(Encoding.UTF8.GetBytes(S3SecretKey));
			var encodedPolicy = Encoding.UTF8.GetBytes(policy);
			var hashedPolicy = sha.ComputeHash(encodedPolicy);
			return Convert.ToBase64String(hashedPolicy);
		}


		private SPList GetDocumentLibrary(string listId)
		{
			SPWeb site = this.Web;
			SPList documentList = null;

			SPSecurity.RunWithElevatedPrivileges(delegate()
			{
				using (SPSite elevatedSite = new SPSite(site.Site.ID))
				{
					foreach (SPWeb elevatedWeb in elevatedSite.AllWebs)
					{

						try
						{
							documentList = elevatedWeb.Lists.GetList(new Guid(listId), false);
						}
						catch { }

						elevatedWeb.Dispose();
					}
				}
			});

			return documentList;
		}
	}
}
